package com.gzx.plugin.tjzy.modular.call.predict.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gzx.plugin.tjzy.modular.call.api.bo.GzxHtCallApiBo;
import com.gzx.plugin.tjzy.modular.call.api.service.GzxHtCallApiService;
import com.gzx.plugin.tjzy.modular.call.predict.bo.GzxPredictCallQueryBo;
import com.gzx.plugin.tjzy.modular.call.predict.consts.GzxHtSwitchTaskType;
import com.gzx.plugin.tjzy.modular.call.predict.entity.GzxPredictCall;
import com.gzx.plugin.tjzy.modular.call.predict.entity.GzxPredictCallDetail;
import com.gzx.plugin.tjzy.modular.call.predict.enums.GzxCallBatchStatusEnum;
import com.gzx.plugin.tjzy.modular.call.predict.service.GzxPredictCallDbService;
import com.gzx.plugin.tjzy.modular.call.predict.service.GzxPredictCallService;
import com.gzx.plugin.tjzy.modular.call.predict.vo.GzxPredictCallDetailVo;
import com.gzx.plugin.tjzy.modular.call.predict.vo.GzxPredictCallVo;
import com.gzx.plugin.tjzy.modular.call.receipt.entity.GzxHtCallReceiptBusiness;
import com.gzx.plugin.tjzy.modular.call.receipt.mapper.GzxHtCallReceiptBusinessMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.consts.IntConstant;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.pojo.CommonResult;
import vip.xiaonuo.common.util.CommonCryptogramUtil;
import vip.xiaonuo.common.util.CommonDateUtil;
import vip.xiaonuo.sys.feign.SysUserFeign;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zjt
 * @description
 * @date 2025/3/28 11:14
 */
@Service
@Slf4j
@RequiredArgsConstructor
@DS("tjzy-async")
public class GzxPredictCallServiceImpl implements GzxPredictCallService {

    private final GzxPredictCallDbService predictCallDbService;

    private final GzxHtCallApiService predictHttpService;

    private final GzxHtCallReceiptBusinessMapper htCallReceiptBusinessMapper;

    private final CommonCacheOperator cacheOperator;

    private final SysUserFeign userFeign;

    /**
     * 分页查询批次表
     *
     * @param predictCallQueryBo
     * @return
     */
    @Override
    public Page<GzxPredictCallVo> pageList(GzxPredictCallQueryBo predictCallQueryBo) {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isNotEmpty(predictCallQueryBo.getDirectorId())) {
            sb.append(predictCallQueryBo.getDirectorId()).append(",");
            //根据主管id获取主管下的所有人
            List<String> userIdList = userFeign.getUserIdByDirectorId(predictCallQueryBo.getDirectorId());
            for (String userId : userIdList) {
                sb.append(userId).append(",");
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        return predictCallDbService.selectVoPage(new Page<>(predictCallQueryBo.getCurrent(), predictCallQueryBo.getSize()),
                Wrappers.<GzxPredictCall>lambdaQuery()
                        .eq(GzxPredictCall::getCallType, predictCallQueryBo.getCallType())
                        .eq(predictCallQueryBo.getCreateUser() != null, GzxPredictCall::getCreateUser, predictCallQueryBo.getCreateUser())
                        .eq(predictCallQueryBo.getCreateDept() != null, GzxPredictCall::getCreateDept, predictCallQueryBo.getCreateDept())
                        .eq(predictCallQueryBo.getBatchStatus() != null, GzxPredictCall::getBatchStatus, predictCallQueryBo.getBatchStatus())
                        //根据主管id获取主管下的所有人
                        .in(StringUtils.isNotEmpty(predictCallQueryBo.getDirectorId()), GzxPredictCall::getCreateUser, sb.toString())
                        //新增taskId查询
                        .eq(StringUtils.isNotBlank(predictCallQueryBo.getTaskId()), GzxPredictCall::getTaskId, predictCallQueryBo.getTaskId())
                        //预测外呼新增日期区间查询
                        .between(StringUtils.isNotBlank(predictCallQueryBo.getBeginTime()) && StringUtils.isNotBlank(predictCallQueryBo.getEndTime()), GzxPredictCall::getCreateTime, predictCallQueryBo.getBeginTime(), predictCallQueryBo.getEndTime())
                        .orderByDesc(GzxPredictCall::getId));
    }

    /**
     * 分页查询预测外呼详情
     *
     * @param predictCallQueryBo
     * @return
     */
    @Override
    public Page<GzxPredictCallDetailVo> pageDetail(GzxPredictCallQueryBo predictCallQueryBo) {
        return predictCallDbService.selectDetailVoPage(new Page<>(predictCallQueryBo.getCurrent(), predictCallQueryBo.getSize()), Wrappers.<GzxPredictCallDetail>lambdaQuery()
                .eq(GzxPredictCallDetail::getBatchNumber, predictCallQueryBo.getBatchNumber())
                .eq(StringUtils.isNotBlank(predictCallQueryBo.getPhone()), GzxPredictCallDetail::getLiaisonPhone, CommonCryptogramUtil.doSm1AesEncrypt(predictCallQueryBo.getPhone()))
                .orderByDesc(GzxPredictCallDetail::getId));
    }

    /**
     * 查询预测外呼
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public List<GzxPredictCallDetail> selectList(LambdaQueryWrapper<GzxPredictCallDetail> queryWrapper) {
        return predictCallDbService.selectDetailList(queryWrapper);
    }

    /**
     * 根据ID获取预测外呼明细数据
     *
     * @param id
     * @return
     */
    @Override
    public GzxPredictCallDetailVo getCallDetailById(Long id) {
        return predictCallDbService.selectDetailVoById(id);
    }

    /**
     * 删除预测外呼
     *
     * @param batchNumber
     */
    @Override
    public String delPredictCall(String batchNumber) {
        //批次状态0待开始1进行中2终止/暂停3全部完成
        try {
            GzxPredictCall predictCall = predictCallDbService.selectOne(Wrappers.<GzxPredictCall>lambdaQuery()
                    .eq(GzxPredictCall::getBatchNumber, batchNumber)
                    .in(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.PENDING.getCode(), GzxCallBatchStatusEnum.CANCELLED.getCode()));
            if (predictCall == null) {
                throw new CommonException("当前批次状态不符合任务删除要求");
            }
            //校验删除逻辑
            SaBaseLoginUser user = StpLoginUserUtil.getLoginUser();
            List<String> roleList = user.getRoleCodeList();
            //此功能必须给用户授权 “分公司主管” 角色
            //自己：当前条数据的createUser == 当前登录人的 用户id
            //主管：当前登录人的角色是主管 && 当前条数据的 createDept == 当前登录人的 createDept
            if (user.getId().equals(predictCall.getCreateUser()) || (user.getOrgId().equals(predictCall.getCreateDept()) && roleList.contains("branchManager"))) {
                deletePreOut(batchNumber);
            } else {
                throw new CommonException("无权删除他人单据");
            }
        } catch (Exception e) {
            throw new CommonException("无权删除他人单据");
        }
        return CommonResult.ok().getMsg();
    }

    /**
     * 开始任务
     *
     * @param batchNumber
     */
    @Override
    public CommonResult<String> startCallTask(String batchNumber) {
        String catchBatchNumber = cacheOperator.getCatchString(batchNumber);
        if (StringUtils.isNotBlank(catchBatchNumber)) {
            return CommonResult.error("任务已开始，请勿重复点击");
        }
        GzxPredictCall predictCall = predictCallDbService.selectOne(Wrappers.<GzxPredictCall>lambdaQuery()
                .eq(GzxPredictCall::getBatchNumber, batchNumber)
                .eq(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.PENDING.getCode()));
        if (predictCall == null) {
            return CommonResult.error("只能开始一次，请重新上传");
        }
        if (!predictCall.getCreateUser().equals(StpLoginUserUtil.getLoginUser().getId())) {
            return CommonResult.error("无权限操作他人上传的数据");
        }
        cacheOperator.setCatchString(batchNumber, batchNumber, IntConstant.VALUE_300);
        predictCall.setBatchStatus(GzxCallBatchStatusEnum.IN_PROGRESS.getCode());
        GzxHtCallApiBo predictCallHttpApiBo = new GzxHtCallApiBo();
        predictCallHttpApiBo.setCallPhone(predictCall.getCaller());
        predictCallHttpApiBo.setCallThread(predictCall.getCallThread());
        predictCallHttpApiBo.setQueueCode(predictCall.getQueueCode());
        predictCallHttpApiBo.setCallType(predictCall.getCallType());
        List<GzxPredictCallDetail> predictCallDetailList = predictCallDbService.selectDetailList(Wrappers.<GzxPredictCallDetail>lambdaQuery()
                .eq(GzxPredictCallDetail::getBatchNumber, batchNumber));
        Map<String, String> bussinesMap = predictCallDetailList.stream().collect(Collectors.toMap(GzxPredictCallDetail::getLiaisonPhone, s -> String.valueOf(s.getId()), (oldVal, newVal) -> newVal));
        predictCallHttpApiBo.setBussinesMap(bussinesMap);
        String taskId = predictHttpService.startPreCall(predictCallHttpApiBo);
        if (StringUtils.isBlank(taskId)) {
            return CommonResult.error("开启预测外呼任务失败");
        }
        predictCall.setTaskId(taskId);
        predictCallDbService.updateById(predictCall);
        predictCallDbService.updateDetail(Wrappers.<GzxPredictCallDetail>lambdaUpdate()
                .set(GzxPredictCallDetail::getTaskId, taskId)
                .eq(GzxPredictCallDetail::getBatchNumber, batchNumber));
        return CommonResult.ok();
    }

    /**
     * 暂停预测外呼任务
     *
     * @param batchNumber
     */
    @Override
    public CommonResult<String> pauseCallTask(String batchNumber) {
        GzxPredictCall predictCall = predictCallDbService.selectOne(Wrappers.<GzxPredictCall>lambdaQuery()
                .eq(GzxPredictCall::getBatchNumber, batchNumber)
                .eq(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.IN_PROGRESS.getCode()));
        if (predictCall == null) {
            return CommonResult.error("当前批次状态不符合任务作废要求");
        }
        if (!predictCall.getCreateUser().equals(StpLoginUserUtil.getLoginUser().getId())) {
            return CommonResult.error("无权限操作他人上传的数据");
        }
        predictCall.setBatchStatus(GzxCallBatchStatusEnum.PAUSED.getCode());
        predictCallDbService.updateById(predictCall);
        predictHttpService.switchTask(predictCall.getTaskId(), GzxHtSwitchTaskType.PAUSE);
        return CommonResult.ok();
    }

    /**
     * 继续预测外呼任务
     *
     * @param batchNumber
     */
    @Override
    public CommonResult<String> continueCallTask(String batchNumber) {
        GzxPredictCall predictCall = predictCallDbService.selectOne(Wrappers.<GzxPredictCall>lambdaQuery()
                .eq(GzxPredictCall::getBatchNumber, batchNumber)
                .eq(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.PAUSED.getCode()));
        if (predictCall == null) {
            return CommonResult.error(batchNumber + "不存在");
        }
        if (CommonDateUtil.compareDateWithSpecifiedDays(predictCall.getCreateTime(), -3)) {
            return CommonResult.error("数据已过期，请重新导入");
        }
        if (predictCall.getBatchStatus() != 2) {
            return CommonResult.error("当前批次状态不符合任务继续要求");
        }
        if (StringUtils.isBlank(predictCall.getTaskId())) {
            return CommonResult.error(batchNumber + "任务ID为空");
        }
        predictHttpService.switchTask(predictCall.getTaskId(), GzxHtSwitchTaskType.START);
        predictCall.setBatchStatus(GzxCallBatchStatusEnum.IN_PROGRESS.getCode());
        predictCallDbService.updateById(predictCall);
        return CommonResult.ok();
    }

    /**
     * 完成预测外呼任务
     *
     * @param batchNumber
     */
    @Override
    public void finishCallTask(String batchNumber) {
        //查询今天的预测外呼任务的
        List<GzxPredictCall> predictCallList = predictCallDbService.selectList(Wrappers.<GzxPredictCall>lambdaQuery()
                .select(GzxPredictCall::getId, GzxPredictCall::getTaskId, GzxPredictCall::getCreateUser)
                .between(StringUtils.isBlank(batchNumber), GzxPredictCall::getCreateTime, CommonDateUtil.getOffsetDateStr(-3) + " 00:00:00", CommonDateUtil.getOffsetDateStr(-3) + " 23:59:59")
                .eq(StringUtils.isNotBlank(batchNumber), GzxPredictCall::getBatchNumber, batchNumber));
        if (CollectionUtil.isNotEmpty(predictCallList)) {
            if (StringUtils.isNotBlank(batchNumber) && !predictCallList.getFirst().getCreateUser().equals(StpLoginUserUtil.getLoginUser().getId())) {
                throw new CommonException("无权作废他人单据");
            }
            Set<String> taskIdSet = predictCallList.stream().map(GzxPredictCall::getTaskId).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
            for (String taskId : taskIdSet) {
                predictHttpService.switchTask(taskId, GzxHtSwitchTaskType.FINISH);
            }
            List<Long> idList = predictCallList.stream().map(GzxPredictCall::getId).toList();
            predictCallDbService.update(Wrappers.<GzxPredictCall>lambdaUpdate()
                    .setSql("batch_status = if(total_count = completed_count, 3, 4)")
                    .in(GzxPredictCall::getId, idList));
        }
    }

    /**
     * 关闭任务
     *
     * @param taskId
     */
    @Override
    public void closeErrorTask(String taskId) {
        predictHttpService.switchTask(taskId, GzxHtSwitchTaskType.FINISH);
    }

    /**
     * 获取批次下接听的数量
     *
     * @param taskId
     * @param filterType
     * @return
     */
    @Override
    public int getCallCount(String taskId, Integer filterType) {
        if (filterType == 0) {
            return 0;
        }
        Long count = htCallReceiptBusinessMapper.selectCount(
                Wrappers.<GzxHtCallReceiptBusiness>lambdaQuery()
                        .select(GzxHtCallReceiptBusiness::getId)
                        .eq(GzxHtCallReceiptBusiness::getTaskId, taskId)
                        .gt(filterType == 1, GzxHtCallReceiptBusiness::getCallDuration, 0));
        return count.intValue();
    }

    /**
     * 删除预测外呼
     */
    public void deletePreOut(String batchNumber) {
        //根据批次号修改主表delete_flag
        predictCallDbService.delete(new LambdaUpdateWrapper<GzxPredictCall>().eq(GzxPredictCall::getBatchNumber, batchNumber));
        //根据批次号删除子表delete_flag
        predictCallDbService.deleteDetail(new LambdaUpdateWrapper<GzxPredictCallDetail>().eq(GzxPredictCallDetail::getBatchNumber, batchNumber));
    }
}
